Load Balancing: Add a second EC2 Instance

Objective#

  • Run our application on more than one EC2 instance.

Steps#

  • Add a second EC2 instance.

Currently, our application is running on a single EC2 instance. To allow our application to scale beyond the capacity of a single instance, we need to introduce a load balancer that can direct traffic to multiple instances.

Adding a second instance#

We could naively add a second instance by simply duplicating the configuration we have for our existing instance. But that would create a lot of configuration duplication. Instead, we’re going to pull the bulk of the EC2 configuration into an EC2 launch template, and then we’ll simply reference the launch template from both instances.

We can almost copy our EC2 instance configuration into a new launch template resource as is, but there are slight differences between the two specifications. In addition, we’ll also need to change the cfn-init and cfn-signal calls at the end of the UserData script to dynamically determine the instance ID at runtime.

main.yml

Line #30: See the next code listing for how to fill in this part.

Now let’s update the UserData script.

main.yml

Line #39: We’re using the Instance Metadata service to get the instance id.

Line #41: Here, we’re getting the tags associated with this instance. The aws:cloudformation:logical-id tag is automatically attached by CloudFormation. Its value is what we pass to cfn-signal to signal a successful launch.

Line #41: Note the usage of ${!INSTANCE_ID}. Since this is inside a CloudFormation !Sub, if we used ${INSTANCE_ID}, CloudFormation would have tried to do the substitution itself. Adding the ! tells CloudFormation to rewrite it for bash to interpret.

Now, we can change our instance resource to reference the new launch template.

main.yml

Line #10: Each time we update our launch template, it will get a new version number. We always want to use the latest.

Adding a second instance is now as easy as creating a new instance resource that references the same launch template.

main.yml

We also need to add an inline IAM policy to allow the UserData script to access the EC2 DescribeTags API. Let’s modify the InstanceRole resource to add it.

main.yml

Line #16: This policy allows our instance to query EC2 for tags.

Now, we can change the output of our CloudFormation template to return a URL for both instances.

main.yml

Finally, let’s change our deploy-infra.sh script to give us these URLs.

deploy-infra.sh

If we run the deploy-infra.sh script now, we should see a pair of URLs when the deployment finishes.

terminal

Our old instance should have been terminated, and two new instances should have started in its place.

At this point, let’s also checkpoint our progress into GitHub.

terminal

Next, let’s modify our application a little bit to allow us to see how our requests get routed. We can do this by simply including the hostname in the response message.

server.js

Line #3: Changes the message to include the hostname.

Let’s push this change to GitHub and wait for the deployment to finish.

terminal

We can follow the deployment progress from the CodePipeline console. Once the deployment is complete, we can verify our change by making a request to both URLs.

terminal

🔍 The hostname that the server is printing is not the same as the Public DNS assigned to the instance. It is actually a private domain name that EC2 assigns to each instance. You can find this private domain in the EC2 console under the Private DNS field.

Note: All the code has been already added and we are pushing it on our repository as well.

Please provide values for the following:
username
Not Specified...
AWS_ACCESS_KEY_ID
Not Specified...
AWS_SECRET_ACCESS_KEY
Not Specified...
AWS_REGION
us-east-1
Github_Token
Not Specified...
/
server.js
main.yml
github.sh
setup.yml
deploy-infra.sh
stop-service.sh
start-service.sh
buildspec.yml
appspec.yml

In order to get a pictorial view of our developed cloudformation stack so far, below is the design view which shows the resources we created and their relationships.

Add a second EC2 instance
Add a second EC2 instance

Let’s go ahead and add a load balancer to have a single endpoint for our application in the next part of this lesson.

Automatic Deployments: Create a CodePipeline
Load Balancing: Add an Application Load Balancer
Mark as Completed
Report an Issue